package space.lzhq.playground;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * SOAP 请求对象
 *
 * @author lzhq
 */
public class SoapRequest {

    private static final String CONTENT_TYPE = "text/xml;charset=";

    private Charset charset = StandardCharsets.UTF_8;

    private String url;

    private String namespace;

    private String method;

    private String methodPrefix;

    private Map<String, Object> params;

    public SoapRequest() {
    }

    public SoapRequest(String url, String namespace) {
        this.url = url;
        this.namespace = namespace;
    }

    public SoapRequest setCharset(Charset charset) {
        this.charset = charset;
        return this;
    }

    public SoapRequest setUrl(String url) {
        this.url = url;
        return this;
    }

    public SoapRequest setNamespace(String namespace) {
        this.namespace = namespace;
        return this;
    }

    public SoapRequest setMethod(String method) {
        this.method = method;
        return this;
    }

    public SoapRequest setMethodPrefix(String methodPrefix) {
        this.methodPrefix = methodPrefix;
        return this;
    }

    public SoapRequest setMethod(String method, String prefix) {
        this.method = method;
        this.methodPrefix = prefix;
        return this;
    }

    public SoapRequest setParams(Map<String, Object> params) {
        this.params = params;
        return this;
    }

    public SoapRequest addParam(String name, Object value) {
        Map<String, Object> params = this.params;
        if (params == null) {
            params = new LinkedHashMap<>();
            this.params = params;
        }

        params.put(name, value);
        return this;
    }

    public String execute() {
        return HttpRequest.post(this.url).body(toSoapXml()).contentType(getContentType()).execute().body();
    }

    private String getContentType() {
        return CONTENT_TYPE + this.charset.toString();
    }

    private String getQualifiedMethod() {
        if (this.methodPrefix == null || this.methodPrefix.trim().isEmpty()) {
            return this.method;
        } else {
            return this.methodPrefix + ":" + this.method;
        }
    }

    private String getMethodXmlns() {
        if (this.methodPrefix == null || this.methodPrefix.trim().isEmpty()) {
            return "xmlns";
        } else {
            return "xmlns" + ":" + this.methodPrefix;
        }
    }

    private String toSoapXml() {
        StringBuilder sb = StrUtil.builder();
        sb.append("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n");
        sb.append("  <soap:Body>\n");

        if (this.method == null || this.method.trim().isEmpty()) {
            throw new IllegalArgumentException("Method must be not blank!");
        }

        sb.append("    <").append(getQualifiedMethod()).append(" ").append(getMethodXmlns()).append("=\"").append(this.namespace).append("\">");
        if (this.params != null) {
            for (Map.Entry<String, Object> entry : this.params.entrySet()) {
                sb.append("      <").append(entry.getKey()).append(">").append(String.valueOf(entry.getValue())).append("</").append(entry.getKey()).append(">");
            }
        }
        sb.append("    </").append(getQualifiedMethod()).append(">");

        sb.append("  </soap:Body>\n");
        sb.append("</soap:Envelope>");
        return sb.toString();
    }
}
